package com.xhwl.data.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xhwl.common.dto.cent.sdata.space.ErrorSpace;
import com.xhwl.common.pojo.ResultJson;
import com.xhwl.common.pojo.cent.sdata.*;
import com.xhwl.common.pojo.cent.sdata.space.RoomOperateLog;
import com.xhwl.common.query.cent.sdata.OrganizationQuery;
import com.xhwl.common.query.cent.sdata.SpaceQuery;
import com.xhwl.data.dao.IOrganizationDao;
import com.xhwl.data.dao.ISpaceDao;
import com.xhwl.data.pojo.space.SpaceImportHandler;
import com.xhwl.data.pojo.space.SpaceOperateDTO;
import com.xhwl.data.service.IOrganizationService;
import com.xhwl.data.service.IOrganizationTypeService;
import com.xhwl.data.service.IRoomOperatorLogService;
import com.xhwl.data.service.ISpaceService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Author: luyi
 * @Description:
 * @Date: Create in 15:41 2021/7/28
 */
@Service
public class SpaceServiceImpl extends ServiceImpl<ISpaceDao, Space> implements ISpaceService {

    @Autowired
    private ISpaceDao spaceDao;

    @Autowired
    private IOrganizationDao organizationDao;

    @Autowired
    private IOrganizationTypeService organizationTypeService;

    @Autowired
    private IOrganizationService organizationService;

    @Autowired
    private SpaceImportHandler spaceImportHandler;

    @Autowired
    private IRoomOperatorLogService roomOperatorLogService;

    private static final Logger log = LoggerFactory.getLogger(SpaceServiceImpl.class);

    @Override
    public Page<Space> page(SpaceQuery spaceQuery, Page page) {
        QueryWrapper<Space> spaceQueryWrapper = new QueryWrapper<>();
        queryHandler(spaceQuery, spaceQueryWrapper);
        return spaceDao.selectPage(page, spaceQueryWrapper);
    }

    private void queryHandler(SpaceQuery spaceQuery, QueryWrapper<Space> spaceQueryWrapper) {
        if (null != spaceQuery) {
            spaceQueryWrapper.orderByAsc("if(sort_field is not null ,sort_field, 100000)","created_at","id");
            if (StringUtils.isNotEmpty(spaceQuery.getKeywords())) {
                spaceQueryWrapper.like("name", spaceQuery.getKeywords());
            }
            if (null != spaceQuery.getParentId()) {
                QueryWrapper<Organization> organizationQueryWrapper = new QueryWrapper<>();
                organizationQueryWrapper.select("id");
                organizationQueryWrapper.eq("parent_id", spaceQuery.getParentId());
                List<Organization> organizations = organizationDao.selectList(organizationQueryWrapper);
                if (!organizations.isEmpty()) {
                    spaceQueryWrapper.in("org_id", organizations.stream().map(o -> o.getId()).collect(Collectors.toList()));
                }else{
                    spaceQueryWrapper.eq("org_id", -1);
                }
            }
            if (null != spaceQuery.getType()) {
                spaceQueryWrapper.eq("type", spaceQuery.getType());
            }
        }
    }

    @Override
    public List<Space> list(SpaceQuery spaceQuery) {
        QueryWrapper<Space> spaceQueryWrapper = new QueryWrapper<>();
        queryHandler(spaceQuery, spaceQueryWrapper);
        return spaceDao.selectList(spaceQueryWrapper);
    }

    @Override
    public ResultJson delete(Integer id) {

        Space space = spaceDao.selectById(id);
        if (null == space) {
            return ResultJson.fail("空间不存在");
        }
        Organization organization = organizationDao.selectById(space.getOrganizationId());
        if (null == organization) {
            log.warn("{} 空间对应的组织数据不存在", space.getOrganizationId());
        }
        QueryWrapper<Organization> organizationQueryWrapper = new QueryWrapper<>();
        organizationQueryWrapper.select("id", "type");
        organizationQueryWrapper.eq("parent_id", space.getOrganizationId());
        List<Organization> organizations = organizationDao.selectList(organizationQueryWrapper);
        if (!organizations.isEmpty()) {
            return ResultJson.fail("存在下级结点，无法删除");
        }
        organizationDao.deleteById(organization.getId());
        spaceDao.deleteById(id);
        return ResultJson.success();
    }

    @Override
    @Transactional
    public ResultJson create(Space space) {

        if (null == space.getParentId()) {
            return ResultJson.fail("缺少上级信息");
        }
        JSONObject spaceData = JSONObject.parseObject(space.getData());
        if (StringUtils.isEmpty((String) spaceData.get("name"))) {
            return ResultJson.fail("缺少名称");
        }
        if (null == space.getId()) {  // 新增
            Organization parent = organizationDao.selectById(space.getParentId());
            if (null == parent) {
                return ResultJson.fail("上级组织不存在");
            }
            QueryWrapper<Space> spaceQueryWrapper = new QueryWrapper<>();
            spaceQueryWrapper.select("id");
            spaceQueryWrapper.eq("name", spaceData.get("name"));
            spaceQueryWrapper.eq("type", space.getType());
            spaceQueryWrapper.eq("project_id", space.getProjectId());
            List<Space> spaces = spaceDao.selectList(spaceQueryWrapper);
            if (CollectionUtils.isNotEmpty(spaces)) {
                log.info("创建自定义空间名称 {} 重复", spaceData.get("name"));
                return ResultJson.fail("名称重复");
            }
			if (StringUtils.isEmpty((String) spaceData.get("code"))) {
				String s = UUID.randomUUID().toString().replaceAll("-", "");
				space.setCode(s);
			}
            Organization organization = new Organization();
            organization.setIndustryId(parent.getIndustryId());
            organization.setEnterpriseId(parent.getEnterpriseId());
            organization.setName((String) spaceData.get("name"));
            organization.setLevel(parent.getLevel() + 1);
            organization.setType(space.getType());
            organization.setParentId(parent.getId());
            organization.setProjectId(parent.getProjectId());
			organization.setCode(space.getCode());
			organization.setSortField(space.getSortField());
            ResultJson resultJson = organizationService.create(organization);
            if(!resultJson.getState()){
                return resultJson;
            }
            space.setOrganizationId(organization.getId());
            space.setProjectId(parent.getProjectId());
            space.setEnterpriseId(parent.getEnterpriseId());
            space.setName((String) spaceData.get("name"));

            spaceDao.insert(space);
            return ResultJson.success(space.getId());
        } else {
            Space old = spaceDao.selectById(space.getId());
            if (null == old) {
                return ResultJson.fail("数据不存在");
            }
            Organization organization = organizationDao.selectById(old.getOrganizationId());
            if (null == organization) {
                return ResultJson.fail("组织" + space.getOrganizationId() + "不存在");
            }
            organization.setName((String) spaceData.get("name"));
            organization.setParentId(space.getParentId());
            if (null != old.getSortField() && !old.getSortField().equals(space.getSortField())){
                List<Organization> organizationList = organizationService.list(new OrganizationQuery().withParentId(organization.getParentId()));
                List<Integer> orgIds = organizationList.stream().filter(i->null != i.getSortField()).map(Organization::getId).collect(Collectors.toList());
                UpdateWrapper<Space> updateWrapper = new UpdateWrapper<>();
                updateWrapper.in("org_id",orgIds);
                UpdateWrapper<Organization> organizationUpdateWrapper = new UpdateWrapper<>();
                organizationUpdateWrapper.in("id",orgIds);
                if (old.getSortField() > space.getSortField()){
                    //大改小 小于等于'大'并且大于等于'小'的加1
                    updateWrapper.ge("sort_field",space.getSortField());
                    updateWrapper.le("sort_field",old.getSortField());
                    organizationUpdateWrapper.ge("sort_field",space.getSortField());
                    organizationUpdateWrapper.le("sort_field",old.getSortField());
                    updateWrapper.setSql("sort_field = sort_field+1");
                    organizationUpdateWrapper.setSql("sort_field = sort_field+1");
                }else {
                    //小改大 大于'小'并且小于等于'大'的减1
                    updateWrapper.le("sort_field",space.getSortField());
                    updateWrapper.gt("sort_field",old.getSortField());
                    organizationUpdateWrapper.le("sort_field",space.getSortField());
                    organizationUpdateWrapper.gt("sort_field",old.getSortField());
                    updateWrapper.setSql("sort_field = sort_field-1");
                    organizationUpdateWrapper.setSql("sort_field = sort_field-1");
                }
                this.update(updateWrapper);
                organizationService.update(organizationUpdateWrapper);
            }
            organizationDao.updateById(organization);
            spaceDao.updateById(space);
        }
        return ResultJson.success();
    }

    @Override
    @Transactional
    public ResultJson batchCreate(List<Space> space) {
        if (CollectionUtils.isEmpty(space)) {
            return ResultJson.fail("参数错误");
        }
        List<Integer> parentOrganizationId = new ArrayList<>(space.size());
        for (Space space1 : space) {
            if (null == space1.getParentId()) {
                return ResultJson.fail("缺少上级id");
            }
            parentOrganizationId.add(space1.getParentId());
        }
        QueryWrapper<Organization> organizationQueryWrapper = new QueryWrapper<>();
        organizationQueryWrapper.select("id", "industry_id", "enterprise_id", "project_id", "level");
        organizationQueryWrapper.eq("is_deleted", 0);
        organizationQueryWrapper.in("id", parentOrganizationId);
        List<Organization> parentCollect = organizationDao.selectList(organizationQueryWrapper);
        if (CollectionUtils.isEmpty(parentCollect)) {
            return ResultJson.fail("上级信息不存在");
        }
        for (Space space1 : space) {
            ResultJson resultJson = this.create(space1);
            if (!resultJson.getState()) {
                log.warn("自定义空间 {} 创建失败", resultJson.getMessage());
            }
        }
        List<Integer> collect = space.stream().map(s -> s.getId()).collect(Collectors.toList());
        return ResultJson.success("创建成功", collect);
    }

    @Override
    public ResultJson nameCheck(Integer id, String name, Integer parentId) {
        if (StringUtils.isEmpty(name)) {
            return ResultJson.fail("名称为空");
        }
        QueryWrapper<Organization> organizationQueryWrapper = new QueryWrapper<>();
        organizationQueryWrapper.select("id");
        organizationQueryWrapper.eq("id", parentId);
        organizationQueryWrapper.eq("is_deleted", false);
        Organization organization = organizationDao.selectOne(organizationQueryWrapper);
        if (null == organization) {
            return ResultJson.fail("上级不存在");
        }
        QueryWrapper<Organization> organizationQueryWrapper1 = new QueryWrapper<>();
        if (null != id) {
            Space space = spaceDao.selectById(id);
            if (null == space) {
                log.warn("空间 {} 数据不存在", id);
                return ResultJson.fail("空间数据不存在");
            }
            organizationQueryWrapper1.ne("id", space.getOrganizationId());
        }
        organizationQueryWrapper1.eq("parent_id", parentId);
        organizationQueryWrapper1.eq("name", name);
        List<Organization> organizations = organizationDao.selectList(organizationQueryWrapper1);
        if (organizations.isEmpty()) {
            return ResultJson.success();
        }
        return ResultJson.fail("名称重复");
    }

	@Override
	@Transactional
    public ResultJson batchCreateFaster(List<Space> spaces, Account account) {
        if(CollectionUtils.isEmpty(spaces)){
            return ResultJson.fail("空数据");
        }
        List<ErrorSpace> errors = new ArrayList<>();
        for(Space space :spaces){
            try {
                ResultJson resultJson = this.create(space);
                if(!resultJson.getState()) {
                    ErrorSpace errorSpace = new ErrorSpace();
                    errorSpace.setReason("保存失败");
                    errorSpace.setObj(space);
                    errors.add(errorSpace);
                }
            } catch (Exception e) {
            }
        }
        /*try {
            this.saveBatch(spaces);
        } catch (Exception e){
            log.error("批量保存失败 {}", e.getMessage());
            for (Space space : spaces) {
                ErrorSpace errorSpace = new ErrorSpace();
                errorSpace.setReason("批量保存失败");
                errorSpace.setObj(space);
                errors.add(errorSpace);
            }
        }*/
		/*List<ErrorSpace> errors = new ArrayList<>();
        Map<Integer, List<Space>> spaceMap = spaces.stream().collect(Collectors.groupingBy(Space::getParentId, Collectors.toList()));

		for(Map.Entry<Integer, List<Space>> spaceEntry : spaceMap.entrySet()) {
			Organization parent = organizationDao.selectById(spaceEntry.getKey());
			try {
				this.saveBatch(spaces);
			} catch (Exception e){
				log.error("批量保存失败 {}", e.getMessage());
				for (Space space : spaces) {
					ErrorSpace errorSpace = new ErrorSpace();
					errorSpace.setReason("批量保存失败");
					errorSpace.setObj(space);
					errors.add(errorSpace);
				}
			}

			// 保存组织信息
			List<Organization> organizations2 = new ArrayList<>();
			for (Space space : spaces) {
				Organization organization1 = new Organization();
				organization1.setName(space.getName());
				organization1.setParentId(space.getParentId());
				if(com.xhwl.common.utils.StringUtils.isEmpty(space.getCode())){
					String s = UUID.randomUUID().toString().replaceAll("-", "");
					space.setCode(s);
				}
				organization1.setCode(space.getCode());
				organization1.setType(space.getType());
				organization1.setLevel(parent.getLevel() + 1);
				organization1.setIndustryId(parent.getIndustryId());
				organization1.setEnterpriseId(parent.getEnterpriseId());
				if(null != parent.getProjectId()){
					organization1.setProjectId(parent.getProjectId());
				}
				organizations2.add(organization1);
			}
			organizationService.saveBatch(organizations2);

			// 统一分组下名称不会重复
			Map<String, Integer> collect1 = organizations2.stream().collect(Collectors.toMap(Organization::getName, Organization::getId,(oldValue,newValue)->newValue));

			for (Space space : spaces) {
				space.setOrganizationId(collect1.get(space.getName()));
			}
			this.updateBatchById(spaces);
		}*/

        return ResultJson.success(errors);
    }


    @Override
    public ResultJson batchImportSpace(MultipartFile file, Integer type, Integer projectId, Account account) {
        spaceImportHandler.emport(file, type, projectId, account);
        return ResultJson.success();
    }

    @Override
    public Space detail(Integer id) {
        return spaceDao.selectById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResultJson split(SpaceOperateDTO spaceOperateDTO) {
        if(CollectionUtils.isEmpty(spaceOperateDTO.getIds())){
            return ResultJson.fail("缺少id");
        }
        if(CollectionUtils.isEmpty(spaceOperateDTO.getSpace())){
            return ResultJson.fail("缺少房间数据");
        }
        if(spaceOperateDTO.getSpace().size() < 2){
            return ResultJson.fail("房间数量错误");
        }
        Space space = spaceDao.selectById(spaceOperateDTO.getIds().get(0));
        if(null == space){
            return ResultJson.fail("房间不存在");
        }
        Organization organization = organizationService.getById(space.getOrganizationId());
        List<Space> spaces = spaceOperateDTO.getSpace();
        List<String> checkList = new ArrayList<>();
        //校验
        for(Space vo : spaces){
            if (null == vo.getParentId()) {
                return ResultJson.fail("缺少上级信息");
            }
            JSONObject spaceData = JSONObject.parseObject(vo.getData());
            if (StringUtils.isEmpty((String) spaceData.get("name"))) {
                return ResultJson.fail("缺少名称");
            }
            Organization parent = organizationDao.selectById(vo.getParentId());
            if (null == parent) {
                return ResultJson.fail("上级组织不存在");
            }
            QueryWrapper<Space> spaceQueryWrapper = new QueryWrapper<>();
            spaceQueryWrapper.select("id");
            spaceQueryWrapper.eq("name", spaceData.get("name"));
            spaceQueryWrapper.eq("type", vo.getType());
            spaceQueryWrapper.eq("project_id", vo.getProjectId());
            List<Space> checkSpaces = spaceDao.selectList(spaceQueryWrapper);
            if (CollectionUtils.isNotEmpty(checkSpaces)) {
                return ResultJson.fail("名称重复");
            }
            String name = spaceData.get("name").toString() + vo.getType() + vo.getProjectId();
            checkList.add(name);
        }
        if (checkList.size() != spaces.size()) {
            return ResultJson.fail("名称重复");
        }
        //创建房间
        for (Space vo : spaces) {
            vo.setSortField(space.getSortField());
            vo.setParentId(organization.getParentId());
            ResultJson resultJson = this.create(vo);
            if(!resultJson.getState()){
                return ResultJson.fail("创建房间失败");
            }
            if(resultJson != null && resultJson.getResult() != null) {
                Object result = resultJson.getResult();
                vo.setId(Integer.parseInt(result.toString()));
            }
        }
        //清除原有数据
        delete(space.getId());
        // 记录拆分日志
        Space spaceOld = new Space();
        BeanUtils.copyProperties(space, spaceOld);
        spaceOperateDTO.setOld(Arrays.asList(spaceOld));
        spaceOperateDTO.setSpace(spaces);
        saveLog(spaceOperateDTO, 2);
        return ResultJson.success();
    }

    @Override
    public ResultJson merge(SpaceOperateDTO spaceOperateDTO) {
        if(CollectionUtils.isEmpty(spaceOperateDTO.getIds())){
            return ResultJson.fail("缺少id");
        }
        if(2 > spaceOperateDTO.getIds().size()){
            return ResultJson.fail("id参数错误");
        }
        if(CollectionUtils.isEmpty(spaceOperateDTO.getSpace())){
            return ResultJson.fail("合并房间参数错误");
        }
        //查询一个被合并的房间
        List<Space> spaces = this.listByIds(spaceOperateDTO.getIds());
        if(CollectionUtils.isEmpty(spaces)){
            return ResultJson.fail("房间不存在");
        }
        List<Space> spaceList = new ArrayList<>();
        for (Space vo : spaces) {
            Space spaceVo = new Space();
            BeanUtils.copyProperties(vo, spaceVo);
            spaceList.add(spaceVo);
        }
        spaceOperateDTO.setOld(spaceList);
        // 合并的房间
        Space space = spaceOperateDTO.getSpace().get(0);
        Organization org = organizationService.getById(spaces.get(0).getOrganizationId());
        space.setParentId(org.getParentId());
        Space old = spaceDao.selectById(spaceOperateDTO.getOperateId());
        space.setSortField(old.getSortField());
        //创建房间
        ResultJson resultJson = this.create(space);
        if(!resultJson.getState()){
            log.info(resultJson.getMessage());
            return ResultJson.fail("创建房间失败");
        }
        if(resultJson != null && resultJson.getResult() != null) {
            Object result = resultJson.getResult();
            space.setId(Integer.parseInt(result.toString()));
        }
        spaceOperateDTO.setSpace(Arrays.asList(space));
        //删除原来房间
        for (Integer id : spaceOperateDTO.getIds()) {
            delete(id);
        }
        //记录日志
        saveLog(spaceOperateDTO, 1);
        return ResultJson.success();
    }

    @Override
    public ResultJson refreshSort(SpaceQuery spaceQuery) {
        List<Space> spaces = this.list(spaceQuery);
        List<Organization> organizationList = organizationService.list(new OrganizationQuery().withIds(spaces.stream().map(Space::getOrganizationId).collect(Collectors.toList())));
        organizationList = organizationList.stream().distinct().collect(Collectors.toList());
        Map<Integer,Organization> organizationMap = organizationList.stream().collect(Collectors.toMap(Organization::getId, Function.identity()));
//        List<List<Area>> parts = Lists.partition(areas, 500);
        for (int i = 0; i < spaces.size(); i++) {
            spaces.get(i).setSortField(i+1);
            JSONObject jsonObject = JSONObject.parseObject(spaces.get(i).getExpand());
            if (null != jsonObject){
                jsonObject.put("sortField",i+1);
                spaces.get(i).setExpand(jsonObject.toJSONString());
            }
            organizationMap.get(spaces.get(i).getOrganizationId()).setSortField(i+1);
        }
        this.updateBatchById(spaces);
        organizationService.updateBatchById(organizationMap.values());
        return ResultJson.success("刷新成功");
    }

    /**
     * 拆分合并记录
     * @param
     * @param type
     */
    public void saveLog(SpaceOperateDTO spaceOperateDTO, Integer type){
        // 拆分
        if(2 == type){
            List<RoomOperateLog> roomOperateLogs = new ArrayList<>();
            for (Space space : spaceOperateDTO.getSpace()) {
                RoomOperateLog roomOperateLog = new RoomOperateLog();
                roomOperateLog.setOldRoomId(spaceOperateDTO.getIds().get(0));
                roomOperateLog.setName(spaceOperateDTO.getOld().get(0).getName());
                roomOperateLog.setCode(spaceOperateDTO.getOld().get(0).getCode());
                roomOperateLog.setType(2);
                roomOperateLog.setNewRoomId(space.getId());
                roomOperateLogs.add(roomOperateLog);
            }
            roomOperatorLogService.saveBatch(roomOperateLogs);
        }
        // 合并
        if(1 == type){
            List<RoomOperateLog> roomOperateLogs = new ArrayList<>();
            for (Space space : spaceOperateDTO.getOld()) {
                RoomOperateLog roomOperateLog = new RoomOperateLog();
                roomOperateLog.setOldRoomId(space.getId());
                roomOperateLog.setNewRoomId(spaceOperateDTO.getSpace().get(0).getId());
                roomOperateLog.setName(space.getName());
                roomOperateLog.setCode(space.getCode());
                roomOperateLog.setType(1);
                roomOperateLogs.add(roomOperateLog);
            }
            roomOperatorLogService.saveBatch(roomOperateLogs);
        }
    }
}
